package com.pic.mgt.haishin;

import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.time.DateUtils;
import org.springframework.dao.DataAccessException;

import com.pic.mgt.IgxStatus;
import com.pic.mgt.controller.BusinessUnitController;
import com.pic.mgt.dao.AbstractBusinessMgtInfoBean;
import com.pic.mgt.dao.haishin.HaishinBusinessMgtDao;
import com.pic.mgt.dao.haishin.HaishinBusinessMgtInfoBean;
import com.pic.mgt.haishin.unit.AppointedHaishinBusinessUnit;
import com.pic.mgt.haishin.unit.GeneralHaishinBusinessUnit;
import com.pic.mgt.haishin.unit.HaishinBusinessUnit;
import com.pic.mgt.haishin.unit.RedoAppointedHaishinBusinessUnit;
import com.pic.mgt.haishin.unit.RedoGeneralHaishinBusinessUnit;
import com.pic.mgt.log.IgxLog;
import com.pic.mgt.scheduler.SchedulerException;
import com.pic.mgt.unit.Business;
import com.pic.mgt.unit.Redoable;
import com.pic.mgt.utils.LogUtils;

/**
 * [配信控制] 主要是將監控到的業務加入排程中
 * @author 洪政緯
 *
 */
public class HaishinBusinessUnitController extends BusinessUnitController {
	private HaishinScheduler haishinScheduler;
	
	// 若是指示配信的話,要提前 ? 分鐘開始執行 <<2011/10/20 指示配信排程修改 by Timothy>>
	private final int appointedHaishinBusinessPredoThreshold = -20;
	
	@Override
	protected Map<String, Object> getDbBusinessMgtInsertBasicValuesMap(Business business) {
		HaishinBusinessUnit haishinBusinessUnit = (HaishinBusinessUnit)business;
		
		Map<String ,Object> insertValuesMap = new HashMap<String, Object>();
		
		insertValuesMap.put(HaishinBusinessMgtDao._confirmationFile, haishinBusinessUnit.getConfirmationFilename());
		insertValuesMap.put(HaishinBusinessMgtDao._targetFile, haishinBusinessUnit.getTargetFilename());
		insertValuesMap.put(HaishinBusinessMgtDao._type, haishinBusinessUnit.getBusinessType());
		insertValuesMap.put(HaishinBusinessMgtDao._targetFilesize, haishinBusinessUnit.getTargetFile().length());
		insertValuesMap.put(HaishinBusinessMgtDao._status, IgxStatus.BUSINESS_LOADED);
		insertValuesMap.put(HaishinBusinessMgtDao._scheduleExecutionTime, new Timestamp(haishinBusinessUnit.getExecutionTime().getTime()));
		insertValuesMap.put(HaishinBusinessMgtDao._unitName, haishinBusinessUnit.getUnitName());
		
		return insertValuesMap;
	}
	
	@Override
	protected String checkIsEffectiveTerminal(Business business) {
		// 配信這裡不用做 "是否為有效端末" 的確認，所以 always return null。
		return null;
	}
	
	@Override
	public void doBusinessAction(Business business) {
		HaishinBusinessUnit haishinBusinessUnit = (HaishinBusinessUnit)business;
		
		// 加入排程
		Date executionTime = null;
		if (AppointedHaishinBusinessUnit.class.isInstance(haishinBusinessUnit)) {
			/*
			 *  <<2011/10/20 指示配信排程修改 by Timothy>>
			 *  如果是指示配信,就要提前?分鐘執行配信。因為給各端末的指示檔有做時間的分割，
			 *  要提早讓端末把指示檔取走，端末才能準確的在指示的時間上來取檔，而不會delay。
			 */
			executionTime = DateUtils.addMinutes(haishinBusinessUnit.getExecutionTime(),
												 this.appointedHaishinBusinessPredoThreshold);
		}
		else {
			executionTime = haishinBusinessUnit.getExecutionTime();
		}		
		try {
			// ********************** Log **********************
			if (IgxLog.messageLog.isInfoMode()) {
				IgxLog.messageLog.info(this,
						"Scheduling haishin business '{}'.", business
								.getUnitName());
			}
			// ********************** Log **********************
			
			String str[] = haishinScheduler.
						scheduleSimpleBusiness(business, executionTime);
			String scheduleName = str[0];
			String scheduleGroupName = str[1];
			
			// ********************** Log **********************
			if (IgxLog.messageLog.isInfoMode()) {
				IgxLog.messageLog.info(this,
						"Scheduling haishin business '{}' completed. (Schedule name:'{}' ; Schedule group name:'{}')",
						business.getUnitName(), scheduleName, scheduleGroupName);
			}
			// ********************** Log **********************
			
			// 資料庫更新 (table:haishin_business_mgt)
			super.businessMgtDao.updateStatusByUnitName(
					IgxStatus.BUSINESS_SCHEDULED,
					business.getUnitName());
			
			// ********************** Log **********************
			if (IgxLog.messageLog.isTraceMode()) {
				IgxLog.messageLog.trace(this,
						"Update status in db table '{}' for unit '{}' completed.",
						super.businessMgtDao.getClass(),
						haishinBusinessUnit.getUnitName());
			}
			// ********************** Log **********************
		} catch (SchedulerException e) {
			// ********************** Log **********************
			LogUtils.error(this, IgxLog.messageDetailsLog, e);
			// ********************** Log **********************
			
			// ********************** Log **********************
			IgxLog.messageLog.error(this,
					"SUDA-249 Scheduling haishin business '{}' failed.", business
							.getUnitName());
			// ********************** Log **********************
			
			super.unitBackup.removeAndBackupErrorUnit(
							business.getConfirmationFile());
		} catch(DataAccessException e1) {
			// ********************** Log **********************
			IgxLog.messageDetailsLog.error(this, e1.getMessage());
			// ********************** Log **********************
			
			// ********************** Log **********************
			IgxLog.messageLog.error(this,
					"SUDA-250 Update status in db table '{}' for unit '{}' failed.",
					super.businessMgtDao.getTableName(),
					haishinBusinessUnit.getUnitName());
			// ********************** Log **********************
		}
	}
	
	@Override
	protected Redoable wrapToAnRedoableBusiness(Business business) {
		Redoable redoableBusiness = null;
		
		if (AppointedHaishinBusinessUnit.class.isInstance(business)) {
			redoableBusiness = new RedoAppointedHaishinBusinessUnit((AppointedHaishinBusinessUnit)business);
		}
		else if (GeneralHaishinBusinessUnit.class.isInstance((GeneralHaishinBusinessUnit)business)) {
			redoableBusiness = new RedoGeneralHaishinBusinessUnit((GeneralHaishinBusinessUnit)business);
		}
		
		return redoableBusiness;
	}
	
	@Override
	public AbstractBusinessMgtInfoBean getBusinessMgtInfoBeanInDB(
			String unitName) throws DataAccessException {
		HaishinBusinessMgtDao haishinBusinessMgtDao = (HaishinBusinessMgtDao)super.businessMgtDao;
		
		HaishinBusinessMgtInfoBean haishinBusinessMgtInfoBean =
			haishinBusinessMgtDao.findHaishinBusinessMgtInfoByUnitName(unitName);
		
		if (null == haishinBusinessMgtInfoBean) {
			return null;
		}
		else {
			return haishinBusinessMgtInfoBean;
		}
	}

	// --- getter and setter
	
	public void setHaishinScheduler(HaishinScheduler haishinScheduler) {
		this.haishinScheduler = haishinScheduler;
	}
}
